/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package MyLib;

import java.net.DatagramPacket;
import java.net.InetAddress;
import java.nio.ByteBuffer;

/**
 *
 * @author QuangHau
 */
public class MyPacket {

    private byte type;
    private byte flag;
    private short length;
    private short checksum;
    private int syn;
    private int ack;
    private byte[] data;

    public MyPacket() {
        this.type = 0;
        this.flag = 0;
        this.length = 0;
        this.checksum = 0;
        this.syn = 0;
        this.ack = 0;
        this.data = null;
    }

    public MyPacket(DatagramPacket Packet) {
        //get header
        byte[] header = new byte[14];
        System.arraycopy(Packet.getData(), 0, header, 0, 14);

        //get type
        this.type = header[0];

        //get flag
        this.flag = header[1];

        //get lenght
        byte[] arr = {header[2], header[3]};
        ByteBuffer wrapped = ByteBuffer.wrap(arr); // big-endian by default
        this.length = wrapped.getShort();

        //get check sum
        arr = new byte[]{header[4], header[5]};
        wrapped = ByteBuffer.wrap(arr); // big-endian by default
        this.checksum = wrapped.getShort();

        //get syn
        arr = new byte[]{header[6], header[7], header[8], header[9]};
        wrapped = ByteBuffer.wrap(arr); // big-endian by default
        this.syn = wrapped.getInt();

        //get ack
        arr = new byte[]{header[10], header[11], header[12], header[13]};
        wrapped = ByteBuffer.wrap(arr); // big-endian by default
        this.ack = wrapped.getInt();

        //get data   
        byte[] data = new byte[this.length];
        System.arraycopy(Packet.getData(), 14, data, 0, this.length);
        this.data = data;
    }

    public static DatagramPacket createPacket(byte[] data_Send, InetAddress _ipAddress, int _port, byte type, byte option, int seq, int ack) {

        /*----Tạo header-----*/
        byte[] header_Send = new byte[14];
        //type: yêu cầu download
        header_Send[0] = type;

        //flag
        header_Send[1] = option;
        if (option == 1) {
            //seq
            ByteBuffer dbufSeq = ByteBuffer.allocate(4);
            dbufSeq.putInt(seq);
            byte[] bytetSeq = dbufSeq.array();
            System.arraycopy(bytetSeq, 0, header_Send, 6, 4);

            //ack
            ByteBuffer dbufAck = ByteBuffer.allocate(4);
            dbufAck.putInt(ack);
            byte[] bytetAck = dbufAck.array();
            System.arraycopy(bytetAck, 0, header_Send, 10, 4);
        }


        //lenght
        short num = (short) (data_Send.length);
        ByteBuffer dbuf = ByteBuffer.allocate(2);
        dbuf.putShort(num);
        byte[] lenght = dbuf.array();
        System.arraycopy(lenght, 0, header_Send, 2, 2);

        //checksum
        short checksum = checksum(data_Send, data_Send.length);
        ByteBuffer ckbuf = ByteBuffer.allocate(2);
        ckbuf.putShort(checksum);
        byte[] lenghtChecksum = ckbuf.array();
        System.arraycopy(lenghtChecksum, 0, header_Send, 4, 2 );
        
        /*----Tạo gói tin-----*/
        byte[] sendData = new byte[1024];
        //gắn header
        System.arraycopy(header_Send, 0, sendData, 0, 14);
        //gắn data

        System.arraycopy(data_Send, 0, sendData, 14, data_Send.length);

        return new DatagramPacket(sendData, sendData.length, _ipAddress, _port);
    }

    /**
     * @return the type
     */
    public byte getType() {
        return type;
    }

    /**
     * @param type the type to set
     */
    public void setType(byte type) {
        this.type = type;
    }

    /**
     * @return the flag
     */
    public byte getFlag() {
        return flag;
    }

    /**
     * @param flag the flag to set
     */
    public void setFlag(byte flag) {
        this.flag = flag;
    }

    /**
     * @return the length
     */
    public short getLength() {
        return length;
    }

    /**
     * @param length the length to set
     */
    public void setLength(short length) {
        this.length = length;
    }

    /**
     * @return the checksum
     */
    public short getChecksum() {
        return checksum;
    }

    /**
     * @param checksum the checksum to set
     */
    public void setChecksum(short checksum) {
        this.checksum = checksum;
    }

    /**
     * @return the syn
     */
    public int getSyn() {
        return syn;
    }

    /**
     * @param syn the syn to set
     */
    public void setSyn(int syn) {
        this.syn = syn;
    }

    /**
     * @return the ack
     */
    public int getAck() {
        return ack;
    }

    /**
     * @param ack the ack to set
     */
    public void setAck(int ack) {
        this.ack = ack;
    }

    /**
     * @return the data
     */
    public byte[] getData() {
        return data;
    }

    /**
     * @param data the data to set
     */
    public void setData(byte[] data) {
        this.data = data;
    }
    
    public static short checksum(byte[] buf, int length) {
        short i = 0;
        short sum = 0;
        while (length > 0) {
            sum += (buf[i++] & 0xff) << 8;
            if ((--length) == 0) {
                break;
            }
            sum += (buf[i++] & 0xff);
            --length;
        }

        return (short) ((~((sum & 0xFFFF) + (sum >> 16))) & 0xFFFF);
    }
}
